"""Core review engine for orchestrating code review process."""

import logging
import time
from typing import List, Optional

from ..config import ConfigManager, RepositoryConfig
from ..database import DatabaseManager
from ..email import EmailSender
from ..git import GitManager
from ..gitcode import GitCodeClient
from ..llm import LLMAnalyzer
from ..models import PullRequest, ReviewResult

logger = logging.getLogger(__name__)


class ReviewEngine:
    """Core review engine."""

    def __init__(
        self, config_manager: ConfigManager, force_review: bool = False, review_date=None
    ):
        """
        Initialize review engine.

        Args:
            config_manager: Configuration manager instance
            force_review: If True, force re-review of PRs already reviewed today
            review_date: Specific date to review PRs created on (datetime.date). None means today
        """
        self.config_manager = config_manager
        self.force_review = force_review
        self.review_date = review_date
        self.gitcode_client = None
        self.db_manager = None
        self.email_sender = None
        self._initialize_components()

    def _initialize_components(self) -> None:
        """Initialize all components."""
        # Initialize GitCode client
        gitcode_config = self.config_manager.get_gitcode_config()
        self.gitcode_client = GitCodeClient(
            api_base_url=gitcode_config["api_base_url"],
            access_token=gitcode_config["access_token"],
        )

        # Initialize database
        db_config = self.config_manager.get_database_config()
        self.db_manager = DatabaseManager(db_config)

        # Initialize email sender
        email_config = self.config_manager.get_email_config()
        self.email_sender = EmailSender(email_config)

    def review_repository(self, repo_config: RepositoryConfig) -> List[ReviewResult]:
        """
        Review all eligible pull requests in a repository.

        Args:
            repo_config: Repository configuration

        Returns:
            List of ReviewResult objects
        """
        logger.info(f"Starting review for repository: {repo_config.name}")

        results = []

        try:
            # Get pull requests
            pulls = self.gitcode_client.get_pulls(repo_config.name, state="opened")
            
            # Filter by date (today or specified date)
            if self.review_date:
                target_pulls = self.gitcode_client.filter_pulls_by_date(pulls, self.review_date)
                date_str = self.review_date.strftime("%Y-%m-%d")
            else:
                target_pulls = self.gitcode_client.filter_today_pulls(pulls)
                date_str = "today"

            if not target_pulls:
                logger.info(f"No PRs created on {date_str} for {repo_config.name}")
                return results

            # Filter out already reviewed PRs (unless force_review is enabled)
            if self.force_review:
                eligible_pulls = target_pulls
                logger.info(
                    f"Force review enabled: will re-review {len(eligible_pulls)} PRs created on {date_str} for {repo_config.name}"
                )
            else:
                # Check if PR was reviewed on the target date (or today if review_date is None)
                check_date = self.review_date if self.review_date else None
                eligible_pulls = [
                    pr
                    for pr in target_pulls
                    if not self.db_manager.is_pr_reviewed_on_date(
                        repo_config.name, pr.number, check_date
                    )
                ]

                if not eligible_pulls:
                    logger.info(f"All PRs created on {date_str} already reviewed for {repo_config.name}")
                    return results

            # Limit by max_review_per_day
            eligible_pulls = eligible_pulls[: repo_config.max_review_per_day]

            logger.info(
                f"Found {len(eligible_pulls)} eligible PRs to review for {repo_config.name}"
            )

            # Review each PR
            for pr in eligible_pulls:
                try:
                    result = self.review_pull_request(repo_config, pr)
                    if result:
                        results.append(result)
                        self.process_review_result(result)
                except Exception as e:
                    logger.error(f"Failed to review PR {repo_config.name}#{pr.number}: {e}")
                    self.db_manager.log_review_execution(
                        repo_config.name, pr.number, "failed", 0, str(e)
                    )

        except Exception as e:
            logger.error(f"Error reviewing repository {repo_config.name}: {e}")

        return results

    def review_pull_request(
        self, repo_config: RepositoryConfig, pr: PullRequest
    ) -> Optional[ReviewResult]:
        """
        Review a single pull request.

        Args:
            repo_config: Repository configuration
            pr: PullRequest object

        Returns:
            ReviewResult object or None if review failed
        """
        start_time = time.time()
        logger.info(f"Reviewing PR {repo_config.name}#{pr.number}: {pr.title}")

        git_manager = None
        try:
            # Initialize Git manager
            git_manager = GitManager(
                repo_name=repo_config.name,
                ssh_url=repo_config.ssh_url,
                local_path=repo_config.local_path,
            )

            # Ensure repository is cloned
            if not git_manager.ensure_repo_cloned():
                logger.error(f"Failed to clone repository {repo_config.name}")
                return None

            # Update main branch
            git_manager.update_main_branch()

            # Checkout PR branch
            if not git_manager.checkout_pr_branch(pr.number):
                logger.error(f"Failed to checkout PR {pr.number} branch")
                return None

            # Get code diff
            code_diff = git_manager.get_diff()
            if not code_diff:
                logger.warning(f"No diff found for PR {pr.number}")
                code_diff = "No code changes detected"

            # Get associated issues
            issues = self.gitcode_client.get_pull_issues(repo_config.name, pr.number)

            # Initialize LLM analyzer
            llm_config = self.config_manager.get_llm_config()
            llm_analyzer = LLMAnalyzer(llm_config)

            # Perform review
            result = llm_analyzer.review_code(
                repo_name=repo_config.name,
                pr_number=pr.number,
                pr_title=pr.title,
                pr_body=pr.body,
                pr_url=pr.html_url,
                code_diff=code_diff,
                issues=issues,
            )

            execution_time = time.time() - start_time
            logger.info(
                f"Review completed for PR {repo_config.name}#{pr.number} "
                f"in {execution_time:.2f}s (severity: {result.severity})"
            )

            # Log execution
            self.db_manager.log_review_execution(
                repo_config.name, pr.number, "success", execution_time
            )

            return result

        except Exception as e:
            execution_time = time.time() - start_time
            logger.error(f"Error reviewing PR {repo_config.name}#{pr.number}: {e}")
            self.db_manager.log_review_execution(
                repo_config.name, pr.number, "failed", execution_time, str(e)
            )
            return None

        finally:
            # Cleanup PR branch
            if git_manager:
                git_manager.cleanup_pr_branch(pr.number)

    def process_review_result(self, result: ReviewResult) -> None:
        """
        Process review result: save to database and send email if needed.

        Args:
            result: ReviewResult object
        """
        # Save to database
        self.db_manager.save_review_result(result)

        # Generate markdown report
        llm_config = self.config_manager.get_llm_config()
        llm_analyzer = LLMAnalyzer(llm_config)
        markdown_content = llm_analyzer.generate_markdown_report(result)

        # Send email if needed
        review_config = self.config_manager.get_review_config()
        email_sent = self.email_sender.send_review_report(result, markdown_content, review_config)

        if email_sent:
            self.db_manager.mark_email_sent(
                result.repo_name, result.pr_number, result.generated_at
            )

    def run_review(self) -> List[ReviewResult]:
        """
        Run review for all configured repositories.

        Returns:
            List of all ReviewResult objects
        """
        logger.info("Starting review process for all repositories")

        all_results = []
        repositories = self.config_manager.get_repositories()

        if not repositories:
            logger.warning("No repositories configured or enabled")
            return all_results

        for repo_config in repositories:
            if not repo_config.enabled:
                logger.info(f"Skipping disabled repository: {repo_config.name}")
                continue

            try:
                results = self.review_repository(repo_config)
                all_results.extend(results)
            except Exception as e:
                logger.error(f"Error processing repository {repo_config.name}: {e}")

        logger.info(f"Review process completed. Reviewed {len(all_results)} PRs in total")
        return all_results

